package com.leyou.sh.search.service.impl;

import com.leyou.sh.common.exception.LyException;

import com.leyou.sh.item.client.ItemClient;
import com.leyou.sh.item.dto.BrandDTO;
import com.leyou.sh.item.dto.CategoryDTO;
import com.leyou.sh.search.dto.SearchParamDTO;
import com.leyou.sh.search.entity.Goods;
import com.leyou.sh.search.repository.GoodsRepository;
import com.leyou.sh.search.service.SearchService;
import com.leyou.starter.elastic.entity.PageInfo;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import reactor.core.publisher.Mono;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static com.leyou.sh.search.constants.SearchConstants.*;

/**
 * @author balisong_fcs
 * @date 2021/1/5 18:29
 * @desc
 */
@Service
public class SearchServiceImpl implements SearchService {

    @Autowired
    private GoodsRepository goodsRepository;
    @Autowired
    private ItemClient itemClient;

    @Override
    public Mono<List<String>> getSuggest(String key) {
        if (StringUtils.isEmpty(key)) {
            throw new LyException(400, "查询得关键字不能为空");
        }
        //连接es
       return goodsRepository.suggestBySingleField(SUGGESTION_FIELD, key);

    }

    @Override
    public Mono<PageInfo<Goods>> searchGoods(SearchParamDTO request) {
        //构建查询条件得工厂对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //source过滤
        sourceBuilder.fetchSource(DEFAULT_SOURCE_FIELD, new String[0]);
        //抽取的获取queryBuilder的方法
        //QueryBuilder queryBuilder = getQueryBuilder(request);

        sourceBuilder.query(getQueryBuilder(request));
        //分页条件
        sourceBuilder.from(request.getFrom());
        sourceBuilder.size(request.getSize());
        //排序条件
        if (StringUtils.isNotBlank(request.getSortBy())) {
            sourceBuilder.sort(request.getSortBy(), request.getDesc() ? SortOrder.DESC: SortOrder.ASC);
        }
        //高亮条件
        sourceBuilder.highlighter(new HighlightBuilder()
                .field(DEFAULT_SEARCH_FIELD)
                .preTags(DEFAULT_PRE_TAG)
                .postTags(DEFAULT_POST_TAG));
        //执行查询
        return goodsRepository.queryBySourceBuilderForPageHighlight(sourceBuilder);
    }

    private QueryBuilder getQueryBuilder(SearchParamDTO request) {
        //查询条件
        String key = request.getKey();
        if (StringUtils.isBlank(key)) {
            throw new LyException(400, "搜索条件不能为空!");
        }
        QueryBuilder queryBuilder = QueryBuilders.matchQuery(DEFAULT_SEARCH_FIELD, key).operator(Operator.AND);
        return queryBuilder;
    }

    @Override
    public Mono<Map<String, List<? extends Object>>> listFilter(SearchParamDTO request) {
        //构建查询对象的工厂对象
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        //通过抽取的方法,获取条件查询的结果
        //方便后续对查询结果进行聚合
        sourceBuilder.query(getQueryBuilder(request));
        //忽略折叠查询结果中非聚合部分数据
        sourceBuilder.from(0).size(0);

        //对品牌部分进行聚合
        sourceBuilder.aggregation(AggregationBuilders.terms("brandAgg").field("brandId"));
        //对分类部分进行聚合
        sourceBuilder.aggregation(AggregationBuilders.terms("categoryAgg").field("categoryId"));
        //查询得到结果,其中包含聚合结果
        //把Mono<Aggregation> ==>Mono<Map<string,List<?>>>
        Mono<Map<String, List<?>>> filterResult = this.goodsRepository.aggregationBySourceBuilder(sourceBuilder).map(aggregations -> {
            //准备将返回聚合结果封装
            Map<String, List<?>> resultMap = new HashMap<>();
            //从聚合对象中抽取聚合结果
            Terms brandAgg = aggregations.get("brandAgg");
            //从品牌聚合结果中抽取品牌id的集合
            List<Long> brandIds = brandAgg.getBuckets()
                    .stream()
                    .map(bucket -> ((Terms.Bucket) bucket)
                            .getKeyAsNumber()
                            .longValue())
                    .collect(Collectors.toList());
            if (!CollectionUtils.isEmpty(brandIds)) {
              /*  List<String> brandNameList = this.itemClient.queryBrandByIds(brandIds)
                        .stream()
                        .map(BrandDTO::getName)
                        .collect(Collectors.toList());*/
                resultMap.put("品牌", this.itemClient.queryBrandByIds(brandIds));
            }

            Terms categoryAgg = aggregations.get("categoryAgg");
            //获取到聚合后分类id的集合
            List<Long> categoryIds = categoryAgg.getBuckets()
                    .stream()
                    .map(bucket -> ((Terms.Bucket) bucket)
                            .getKeyAsNumber()
                            .longValue())
                    .collect(Collectors.toList());
           /* List<String> categoryNameList = this.itemClient.queryCategoryByIds(categoryIds)
                    .stream()
                    .map(CategoryDTO::getName)
                    .collect(Collectors.toList());*/
            if (!CollectionUtils.isEmpty(categoryIds)) {
                resultMap.put("分类", this.itemClient.queryCategoryByIds(categoryIds));
            }
            return resultMap;

        });
        return filterResult;
    }
}
